/****************************************************************************

 Copyright (C) 2009 Jean Pierre Charalambos. All rights reserved.

 Jean Pierre Charalambos (http://dis.unal.edu.co/profesores/pierre/) is an
 Affiliate Associate Professor of the Faculty of Engineering at National
 University of Colombia (http://www.unal.edu.co/).

 This file is part of maku version 0.2.

 http://code.google.com/p/maku/
 email: jpcharalambosh@unal.edu.co

 This file may be used under the terms of the GNU General Public License
 versions 2.0 or 3.0 as published by the Free Software Foundation and
 appearing in the COPYING file included in the packaging of this file.

 This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

*****************************************************************************/

#ifndef BOUNDINGSPHERET_H
#define BOUNDINGSPHERET_H

#include <CGAL/Cartesian.h>
#include <CGAL/Gmpq.h>
#include <CGAL/Min_sphere_of_spheres_d.h>
#include <vector>

// base class:
#include "boundingsphere.h"

using namespace OpenMesh;

template <typename M>
class BoundingSphereT  : public BoundingSphere {
    public:
        typedef M                                                  Mesh;
        //1st alternative:
        typedef float                                              FT;
        //2nd alternative:
        //typedef CGAL::Gmpq                                         FT;
        typedef CGAL::Cartesian<FT>                                K;
        typedef CGAL::Min_sphere_of_spheres_d_traits_3<K,FT>       Traits;
        typedef CGAL::Min_sphere_of_spheres_d<Traits>              Min_sphere;
        typedef K::Point_3                                         Point;
        typedef Traits::Sphere                                     Sphere;

        BoundingSphereT() : BoundingSphere() {}
        BoundingSphereT ( Mesh & mesh ) {
            setTightBoundingSphere ( mesh );
        };
        virtual ~BoundingSphereT() {}
        virtual void setTightBoundingSphere ( const Mesh & mesh ) {
            std::vector<Sphere> S;                  // n spheres
            FT coord[3];                            // 3 coordinates

            typename Mesh::ConstVertexIter              v_it;

            for ( v_it=mesh.vertices_begin(); v_it!=mesh.vertices_end(); ++v_it ) {
                coord[0] = mesh.point ( v_it.handle() ) [0];
                coord[1] = mesh.point ( v_it.handle() ) [1];
                coord[2] = mesh.point ( v_it.handle() ) [2];
                Point p ( coord[0],coord[1],coord[2] );
                S.push_back ( Sphere ( p,0 ) );
            }

            Min_sphere ms ( S.begin(),S.end() );    // check in the spheres
            CGAL_assertion ( ms.is_valid() );

            //radius
            //1st alternative:
            radius = ms.radius();
            //2nd alternative:
            /**
            double a, b, t;
            t = CGAL::to_double(ms.discriminant());
            a = CGAL::to_double(ms.radius().first);
            b = CGAL::to_double(ms.radius().second);
            radius = (float) (a + ( b*sqrt(t)));
            // */

            //center
            Min_sphere::Cartesian_const_iterator          c_it;
            int i = 0;
            for ( c_it=ms.center_cartesian_begin(); c_it!=ms.center_cartesian_end(); ++c_it ) {
                //1st alternative:
                center[i] = *c_it;
                //2nd alternative:
                /*
                a = CGAL::to_double((*c_it).first);
                b = CGAL::to_double((*c_it).second);
                center[i] = (float) (a + ( b*sqrt(t)));
                // */
                i++;
            }
        }
};

#endif
